/*****************************************************************************************
   
   Copyright (c) Microsoft Corporation. All rights reserved.

   Use of this code sample is subject to the terms of the Microsoft
   Permissive License, a copy of which should always be distributed with
   this file.  You can also access a copy of this license agreement at:
   http://www.microsoft.com/resources/sharedsource/licensingbasics/permissivelicense.mspx

 ****************************************************************************************/

using System;

namespace GrooveWebServicesV12Helpers.Forms
{
	/// <summary>
	/// Represents a Groove Forms tool.
	/// </summary>
	public class FormsTool :
        GrooveWebServicesV12Helpers.Tool,
        GrooveWebServicesV12Helpers.Shared.IGrooveWebServicesEventCallback
    {
		private GrooveFormsWebService.GrooveForms m_GrooveForms;

        internal static System.Collections.SortedList s_FormsToolEventManagerSortedList = new System.Collections.SortedList();
        private int m_FormsToolEventManagerCount = 0;

        private string m_FormsSubscriptionID;

        public FormsTool(GrooveWebServicesV12Helpers.Space i_Space, GrooveToolsWebService.Tool i_Tool)
            : base(i_Space, i_Tool)
        {
            //  Make sure we are dealing with a 3.0 or later Forms tool
            if (this.Type != GrooveWebServicesV12Helpers.Shared.GROOVE_FORMS_TOOL_SUPPORTED_TYPE)
                throw new System.ArgumentException("Invalid tool type: " + this.Type);
        }

		#region Forms Properties And Methods

		public static GrooveFormsWebService.GrooveForms CreateInitializedFormsWebService(string i_IdentityURL, string i_TargetURI, GrooveWebServicesV12Helpers.Context i_Context)
		{
			//  Create the service
			GrooveFormsWebService.GrooveForms FormsWebService = new GrooveFormsWebService.GrooveForms();

			//  Create the Groove SOAP header
			FormsWebService.GrooveRequestHeaderValue = new GrooveFormsWebService.GrooveRequestHeader();

			//  Set appropriate header values
			FormsWebService.GrooveRequestHeaderValue.GrooveRequestKey = i_Context.RequestKey;
			FormsWebService.GrooveRequestHeaderValue.GrooveIdentityURL = i_IdentityURL;

			//  Set the URL
			FormsWebService.Url = i_Context.Host + i_TargetURI;

			//  Set Timeout
			FormsWebService.Timeout = i_Context.Timeout;

			return FormsWebService;
		}

		/// <summary>
		/// Array of Forms defined in the FormsTool.
		/// </summary>
		public GrooveWebServicesV12Helpers.Forms.Form[] Forms
		{
			get
			{
				System.Collections.ArrayList FormsArrayList = new System.Collections.ArrayList();

                //  Get initialized reference to web service
				GrooveFormsWebService.GrooveForms FormsWebService = this.GetInitializedFormsWebService(this.Data);

				System.DateTime BeginDateTime = System.DateTime.Now;

				//  Ask service to provide the list of Forms entries for this tool
				GrooveFormsWebService.Form[] Forms = FormsWebService.ReadForms();

				if (GrooveWebServicesV12Helpers.Context.TraceEnabled)
				{
					System.TimeSpan TimeSpan = System.DateTime.Now.Subtract(BeginDateTime);
					System.Diagnostics.Debug.WriteLine("FormsWebService::ReadForms, " + TimeSpan.TotalMilliseconds + " ms");
				}

				//  Create array list of Forms
				foreach (GrooveFormsWebService.Form Form in Forms)
				{
					GrooveWebServicesV12Helpers.Forms.Form NewForm = new GrooveWebServicesV12Helpers.Forms.Form
						(
						this,
						Form
						);

					FormsArrayList.Add(NewForm);
				}

				//  Return array from array list
				return (GrooveWebServicesV12Helpers.Forms.Form[])FormsArrayList.ToArray(typeof(GrooveWebServicesV12Helpers.Forms.Form));
			}
		}

        /// <summary>
        /// Mark records as "read".
        /// </summary>
        /// <param name="i_RecordURIs">Array of URIs for the records to be marked "read".</param>
        public void MarkRecordsRead(string[] i_RecordURIs)
        {
            this.SetUnreadStatus
                (
                i_RecordURIs,
                false			//  Unread
                );
        }

        /// <summary>
        /// Mark records as "unread".
        /// </summary>
        /// <param name="i_RecordURIs">Array of URIs for the records to be marked "unread".</param>
        public void MarkRecordsUnread(string[] i_RecordURIs)
        {
            this.SetUnreadStatus
                (
                i_RecordURIs,
                true			//  Unread
                );
        }

        /// <summary>
        /// A RecordDataSet containing the schema of the tool.
        /// </summary>
        public GrooveWebServicesV12Helpers.Forms.RecordDataSet Schema
        {
            get
            {
                return int_QueryRecords
                    (
                    "",									//  FieldSchemaScopingElement
                    "All",								//  FieldSchemaScopingFlag
                    "Base64",							//  FileAttachmentFormat
                    "",									//  FormURI
                    false,								//  IncludeFileAttachmentContent,
                    true,								//  QueryMetaDataOnly
                    false,								//  UnreadRecordsOnly
                    "",									//  ViewURI
                    ""									//  WhereClause
                    );
            }
        }

        /// <summary>
        /// A RecordDataSet containing all data records in the tool.
        /// </summary>
        public GrooveWebServicesV12Helpers.Forms.RecordDataSet Records
        {
            get
            {
                return int_QueryRecords
                    (
                    "",									//  FieldSchemaScopingElement
                    "All",								//  FieldSchemaScopingFlag
                    "Base64",							//  FileAttachmentFormat
                    "",									//  FormURI
                    false,								//  IncludeFileAttachmentContent,
                    false,								//  QueryMetaDataOnly
                    false,								//  UnreadRecordsOnly
                    "",									//  ViewURI
                    ""									//  WhereClause
                    );
            }
        }

        /// <summary>
        /// Get data records in the tool.
        /// </summary>
        /// <param name="i_IncludeFileAttachmentContent">true to include file attachment content.</param>
        /// <returns>RecordDataSet</returns>
        public GrooveWebServicesV12Helpers.Forms.RecordDataSet GetRecords(bool i_IncludeFileAttachmentContent)
        {
            return int_QueryRecords
                (
                "",									//  FieldSchemaScopingElement
                "All",								//  FieldSchemaScopingFlag
                "Base64",							//  FileAttachmentFormat
                "",									//  FormURI
                i_IncludeFileAttachmentContent,
                false,								//  QueryMetaDataOnly
                false,								//  UnreadRecordsOnly
                "",									//  ViewURI
                ""									//  WhereClause
                );
        }

        /// <summary>
        /// Get data records in the tool.
        /// </summary>
        /// <param name="i_IncludeFileAttachmentContent">true to include file attachment content.</param>
        /// <param name="i_UnreadRecordsOnly">true to include only "unread" records.</param>
        /// <returns>RecordDataSet</returns>
        public GrooveWebServicesV12Helpers.Forms.RecordDataSet GetRecords(bool i_IncludeFileAttachmentContent, bool i_UnreadRecordsOnly)
        {
            return int_QueryRecords
                (
                "",									//  FieldSchemaScopingElement
                "All",								//  FieldSchemaScopingFlag
                "Base64",							//  FileAttachmentFormat
                "",									//  FormURI
                i_IncludeFileAttachmentContent,
                false,								//  QueryMetaDataOnly
                i_UnreadRecordsOnly,
                "",									//  ViewURI
                ""									//  WhereClause
                );
        }

        /// <summary>
        /// Query for records in the tool.
        /// </summary>
        /// <param name="i_WhereClause">Specifies the condition to select records. The syntax of the clause is similar to an SQL where clause; refer to Groove documentation for details.</param>
        /// <returns>RecordDataSet</returns>
        public GrooveWebServicesV12Helpers.Forms.RecordDataSet QueryRecords(string i_WhereClause)
        {
            return int_QueryRecords
                (
                "",									//  FieldSchemaScopingElement
                "All",								//  FieldSchemaScopingFlag
                "Base64",							//  FileAttachmentFormat
                "",									//  FormURI
                false,								//  IncludeFileAttachmentContent,
                false,								//  QueryMetaDataOnly
                false,								//  UnreadRecordsOnly
                "",									//  ViewURI
                i_WhereClause
                );
        }

        /// <summary>
        /// Query for records in the tool.
        /// </summary>
        /// <param name="i_WhereClause">Specifies the condition to select records. The syntax of the clause is similar to an SQL where clause; refer to Groove documentation for details.</param>
        /// <param name="i_IncludeFileAttachmentContent">true to include file attachment content.</param>
        /// <returns>RecordDataSet</returns>
        public GrooveWebServicesV12Helpers.Forms.RecordDataSet QueryRecords(string i_WhereClause, bool i_IncludeFileAttachmentContent)
        {
            return int_QueryRecords
                (
                "",									//  FieldSchemaScopingElement
                "All",								//  FieldSchemaScopingFlag
                "Base64",							//  FileAttachmentFormat
                "",									//  FormURI
                i_IncludeFileAttachmentContent,
                false,								//  QueryMetaDataOnly
                false,								//  UnreadRecordsOnly
                "",									//  ViewURI
                i_WhereClause
                );
        }

        /// <summary>
        /// Query for records in the tool.
        /// </summary>
        /// <param name="i_WhereClause">Specifies the condition to select records. The syntax of the clause is similar to an SQL where clause; refer to Groove documentation for details.</param>
        /// <param name="i_IncludeFileAttachmentContent">true to include file attachment content.</param>
        /// <param name="i_UnreadRecordsOnly">true to include only "unread" records.</param>
        /// <returns>RecordDataSet</returns>
        public GrooveWebServicesV12Helpers.Forms.RecordDataSet QueryRecords(string i_WhereClause, bool i_IncludeFileAttachmentContent, bool i_UnreadRecordsOnly)
        {
            return int_QueryRecords
                (
                "",									//  FieldSchemaScopingElement
                "All",								//  FieldSchemaScopingFlag
                "Base64",							//  FileAttachmentFormat
                "",									//  FormURI
                i_IncludeFileAttachmentContent,
                false,								//  QueryMetaDataOnly
                i_UnreadRecordsOnly,
                "",									//  ViewURI
                i_WhereClause
                );
        }

        /// <summary>
        /// Query for records in the tool which use a particular form.
        /// </summary>
        /// <param name="i_FormURI">URI of the form</param>
        /// <returns>RecordDataSet</returns>
        public GrooveWebServicesV12Helpers.Forms.RecordDataSet GetFormRecords(string i_FormURI)
        {
            return int_QueryRecords
                (
                i_FormURI,							//  FieldSchemaScopingElement
                "Form",								//  FieldSchemaScopingFlag
                "Base64",							//  FileAttachmentFormat
                i_FormURI,
                false,								//  IncludeFileAttachmentContent
                false,								//  QueryMetaDataOnly
                false,								//  UnreadRecordsOnly
                "",									//  ViewURI
                ""									//  WhereClause
                );
        }

        /// <summary>
        /// Query for records in the tool which use a particular form.
        /// </summary>
        /// <param name="i_FormURI">URI of the form</param>
        /// <param name="i_IncludeFileAttachmentContent">true to include file attachment content.</param>
        /// <returns>RecordDataSet</returns>
        public GrooveWebServicesV12Helpers.Forms.RecordDataSet GetFormRecords(string i_FormURI, bool i_IncludeFileAttachmentContent)
        {
            return int_QueryRecords
                (
                i_FormURI,							//  FieldSchemaScopingElement
                "Form",								//  FieldSchemaScopingFlag
                "Base64",							//  FileAttachmentFormat
                i_FormURI,
                i_IncludeFileAttachmentContent,
                false,								//  QueryMetaDataOnly
                false,								//  UnreadRecordsOnly
                "",									//  ViewURI
                ""									//  WhereClause
                );
        }

        /// <summary>
        /// Query for records in the tool which use a particular form.
        /// </summary>
        /// <param name="i_FormURI">URI of the form</param>
        /// <param name="i_IncludeFileAttachmentContent">true to include file attachment content.</param>
        /// <param name="i_UnreadRecordsOnly">true to include only "unread" records.</param>
        /// <returns>RecordDataSet</returns>
        public GrooveWebServicesV12Helpers.Forms.RecordDataSet GetFormRecords(string i_FormURI, bool i_IncludeFileAttachmentContent, bool i_UnreadRecordsOnly)
        {
            return int_QueryRecords
                (
                i_FormURI,							//  FieldSchemaScopingElement
                "Form",								//  FieldSchemaScopingFlag
                "Base64",							//  FileAttachmentFormat
                i_FormURI,
                i_IncludeFileAttachmentContent,
                false,								//  QueryMetaDataOnly
                i_UnreadRecordsOnly,
                "",									//  ViewURI
                ""									//  WhereClause
                );
        }

        /// <summary>
        /// Query for records in the tool which use a particular form.
        /// </summary>
        /// <param name="i_FormURI">URI of the form</param>
        /// <param name="i_WhereClause">Specifies the condition to select records. The syntax of the clause is similar to an SQL where clause; refer to Groove documentation for details.</param>
        /// <returns>RecordDataSet</returns>
        public GrooveWebServicesV12Helpers.Forms.RecordDataSet QueryFormRecords(string i_FormURI, string i_WhereClause)
        {
            return int_QueryRecords
                (
                i_FormURI,							//  FieldSchemaScopingElement
                "Form",								//  FieldSchemaScopingFlag
                "Base64",							//  FileAttachmentFormat
                i_FormURI,
                false,								//  IncludeFileAttachmentContent
                false,								//  QueryMetaDataOnly
                false,								//  UnreadRecordsOnly
                "",									//  ViewURI
                i_WhereClause
                );
        }

        /// <summary>
        /// Query for records in the tool which use a particular form.
        /// </summary>
        /// <param name="i_FormURI">URI of the form</param>
        /// <param name="i_WhereClause">Specifies the condition to select records. The syntax of the clause is similar to an SQL where clause; refer to Groove documentation for details.</param>
        /// <param name="i_IncludeFileAttachmentContent">true to include file attachment content.</param>
        /// <returns>RecordDataSet</returns>
        public GrooveWebServicesV12Helpers.Forms.RecordDataSet QueryFormRecords(string i_FormURI, string i_WhereClause, bool i_IncludeFileAttachmentContent)
        {
            return int_QueryRecords
                (
                i_FormURI,							//  FieldSchemaScopingElement
                "Form",								//  FieldSchemaScopingFlag
                "Base64",							//  FileAttachmentFormat
                i_FormURI,
                i_IncludeFileAttachmentContent,
                false,								//  QueryMetaDataOnly
                false,								//  UnreadRecordsOnly
                "",									//  ViewURI
                i_WhereClause
                );
        }

        /// <summary>
        /// Query for records in the tool which use a particular form.
        /// </summary>
        /// <param name="i_FormURI">URI of the form</param>
        /// <param name="i_WhereClause">Specifies the condition to select records. The syntax of the clause is similar to an SQL where clause; refer to Groove documentation for details.</param>
        /// <param name="i_IncludeFileAttachmentContent">true to include file attachment content.</param>
        /// <param name="i_UnreadRecordsOnly">true to include only "unread" records.</param>
        /// <returns>RecordDataSet</returns>
        public GrooveWebServicesV12Helpers.Forms.RecordDataSet QueryFormRecords(string i_FormURI, string i_WhereClause, bool i_IncludeFileAttachmentContent, bool i_UnreadRecordsOnly)
        {
            return int_QueryRecords
                (
                i_FormURI,							//  FieldSchemaScopingElement
                "Form",								//  FieldSchemaScopingFlag
                "Base64",							//  FileAttachmentFormat
                i_FormURI,
                i_IncludeFileAttachmentContent,
                false,								//  QueryMetaDataOnly
                i_UnreadRecordsOnly,
                "",									//  ViewURI
                i_WhereClause
                );
        }

        /// <summary>
        /// Query for records in the tool which appear in a particular view.
        /// </summary>
        /// <param name="i_ViewURI">URI of the view</param>
        /// <returns>RecordDataSet</returns>
        public GrooveWebServicesV12Helpers.Forms.RecordDataSet GetViewRecords(string i_ViewURI)
        {
            return int_QueryRecords
                (
                i_ViewURI,							//  FieldSchemaScopingElement
                "View",								//  FieldSchemaScopingFlag
                "Base64",							//  FileAttachmentFormat
                "",									//  FormURI
                false,								//  IncludeFileAttachmentContent
                false,								//  QueryMetaDataOnly
                false,								//  UnreadRecordsOnly
                i_ViewURI,
                ""									//  WhereClause
                );
        }

        /// <summary>
        /// Query for records in the tool which appear in a particular view.
        /// </summary>
        /// <param name="i_ViewURI">URI of the view</param>
        /// <param name="i_IncludeFileAttachmentContent">true to include file attachment content.</param>
        /// <returns>RecordDataSet</returns>
        public GrooveWebServicesV12Helpers.Forms.RecordDataSet GetViewRecords(string i_ViewURI, bool i_IncludeFileAttachmentContent)
        {
            return int_QueryRecords
                (
                i_ViewURI,							//  FieldSchemaScopingElement
                "View",								//  FieldSchemaScopingFlag
                "Base64",							//  FileAttachmentFormat
                "",									//  FormURI
                i_IncludeFileAttachmentContent,
                false,								//  QueryMetaDataOnly
                false,								//  UnreadRecordsOnly
                i_ViewURI,
                ""									//  WhereClause
                );
        }

        /// <summary>
        /// Query for records in the tool which appear in a particular view.
        /// </summary>
        /// <param name="i_ViewURI">URI of the view</param>
        /// <param name="i_IncludeFileAttachmentContent">true to include file attachment content.</param>
        /// <param name="i_UnreadRecordsOnly">true to include only "unread" records.</param>
        /// <returns>RecordDataSet</returns>
        public GrooveWebServicesV12Helpers.Forms.RecordDataSet GetViewRecords(string i_ViewURI, bool i_IncludeFileAttachmentContent, bool i_UnreadRecordsOnly)
        {
            return int_QueryRecords
                (
                i_ViewURI,							//  FieldSchemaScopingElement
                "View",								//  FieldSchemaScopingFlag
                "Base64",							//  FileAttachmentFormat
                "",									//  FormURI
                i_IncludeFileAttachmentContent,
                false,								//  QueryMetaDataOnly
                i_UnreadRecordsOnly,
                i_ViewURI,
                ""									//  WhereClause
                );
        }

        /// <summary>
        /// Query for records in the tool which appear in a particular view.
        /// </summary>
        /// <param name="i_ViewURI">URI of the view</param>
        /// <param name="i_WhereClause">Specifies the condition to select records. The syntax of the clause is similar to an SQL where clause; refer to Groove documentation for details.</param>
        /// <returns>RecordDataSet</returns>
        public GrooveWebServicesV12Helpers.Forms.RecordDataSet QueryViewRecords(string i_ViewURI, string i_WhereClause)
        {
            return int_QueryRecords
                (
                i_ViewURI,							//  FieldSchemaScopingElement
                "View",								//  FieldSchemaScopingFlag
                "Base64",							//  FileAttachmentFormat
                "",									//  FormURI
                false,								//  IncludeFileAttachmentContent
                false,								//  QueryMetaDataOnly
                false,								//  UnreadRecordsOnly
                i_ViewURI,
                i_WhereClause
                );
        }

        /// <summary>
        /// Query for records in the tool which appear in a particular view.
        /// </summary>
        /// <param name="i_ViewURI">URI of the view</param>
        /// <param name="i_WhereClause">Specifies the condition to select records. The syntax of the clause is similar to an SQL where clause; refer to Groove documentation for details.</param>
        /// <param name="i_IncludeFileAttachmentContent">true to include file attachment content.</param>
        /// <returns>RecordDataSet</returns>
        public GrooveWebServicesV12Helpers.Forms.RecordDataSet QueryViewRecords(string i_ViewURI, string i_WhereClause, bool i_IncludeFileAttachmentContent)
        {
            return int_QueryRecords
                (
                i_ViewURI,							//  FieldSchemaScopingElement
                "View",								//  FieldSchemaScopingFlag
                "Base64",							//  FileAttachmentFormat
                "",									//  FormURI
                i_IncludeFileAttachmentContent,
                false,								//  QueryMetaDataOnly
                false,								//  UnreadRecordsOnly
                i_ViewURI,
                i_WhereClause
                );
        }

        /// <summary>
        /// Query for records in the tool which appear in a particular view.
        /// </summary>
        /// <param name="i_ViewURI">URI of the view</param>
        /// <param name="i_WhereClause">Specifies the condition to select records. The syntax of the clause is similar to an SQL where clause; refer to Groove documentation for details.</param>
        /// <param name="i_IncludeFileAttachmentContent">true to include file attachment content.</param>
        /// <param name="i_UnreadRecordsOnly">true to include only "unread" records.</param>
        /// <returns>RecordDataSet</returns>
        public GrooveWebServicesV12Helpers.Forms.RecordDataSet QueryViewRecords(string i_ViewURI, string i_WhereClause, bool i_IncludeFileAttachmentContent, bool i_UnreadRecordsOnly)
        {
            return int_QueryRecords
                (
                i_ViewURI,							//  FieldSchemaScopingElement
                "View",								//  FieldSchemaScopingFlag
                "Base64",							//  FileAttachmentFormat
                "",									//  FormURI
                i_IncludeFileAttachmentContent,
                false,								//  QueryMetaDataOnly
                i_UnreadRecordsOnly,
                i_ViewURI,
                i_WhereClause
                );
        }

		internal GrooveWebServicesV12Helpers.Forms.RecordDataSet int_QueryRecords(string i_FieldSchemaScopingElement, string i_FieldSchemaScopingFlag, string i_FileAttachmentFormat, string i_FormURI, bool i_IncludeFileAttachmentContent, bool i_QueryMetaDataOnly, bool i_UnreadRecordsOnly, string i_ViewURI, string i_WhereClause)
		{
			GrooveWebServicesV12Helpers.Forms.RecordDataSet NewRecordDataSet;

            //  Get initialized reference to web service
			GrooveFormsWebService.GrooveForms FormsWebService = this.GetInitializedFormsWebService(this.Data);

			//  Ask service to provide the list of all records
			GrooveFormsWebService.RecordQuery RecordQuery = new GrooveFormsWebService.RecordQuery();
			RecordQuery.FieldSchemaScopingElement = i_FieldSchemaScopingElement;
			RecordQuery.FieldSchemaScopingFlag = i_FieldSchemaScopingFlag;
			RecordQuery.FileAttachmentFormat = i_FileAttachmentFormat;
			RecordQuery.FormURI = i_FormURI;
			RecordQuery.IncludeFileAttachmentContent = i_IncludeFileAttachmentContent;
			RecordQuery.QueryMetadataOnly = i_QueryMetaDataOnly;
			RecordQuery.UnreadRecordsOnly = i_UnreadRecordsOnly;
			RecordQuery.ViewURI = i_ViewURI;
			RecordQuery.WhereClause = i_WhereClause;

			System.DateTime BeginDateTime = System.DateTime.Now;

			//  Ask service to query records
			GrooveFormsWebService.FormsRecordDataSet FormsRecordDataSet = FormsWebService.QueryRecords(RecordQuery);

			if (GrooveWebServicesV12Helpers.Context.TraceEnabled)
			{
				System.TimeSpan TimeSpan = System.DateTime.Now.Subtract(BeginDateTime);
				System.Diagnostics.Debug.WriteLine("FormsWebService::QueryRecords, " + TimeSpan.TotalMilliseconds + " ms");
			}

			NewRecordDataSet = new GrooveWebServicesV12Helpers.Forms.RecordDataSet(FormsRecordDataSet);
			return NewRecordDataSet;
		}

        /// <summary>
        /// Retrieve a set of records.
        /// </summary>
        /// <param name="i_RecordURIs">Array of record URIs to retrieve.</param>
        /// <returns>RecordDataSet</returns>
        public GrooveWebServicesV12Helpers.Forms.RecordDataSet GetRecords(string[] i_RecordURIs)
        {
            return int_GetRecords
                (
                i_RecordURIs,
                false,
                "Base64",
                false
                );
        }

        /// <summary>
        /// Retrieve a set of records.
        /// </summary>
        /// <param name="i_RecordURIs">Array of record URIs to retrieve.</param>
        /// <param name="i_IncludeFileAttachmentContent">true to include file attachment content.</param>
        /// <returns>RecordDataSet</returns>
        public GrooveWebServicesV12Helpers.Forms.RecordDataSet GetRecords(string[] i_RecordURIs, bool i_IncludeFileAttachmentContent)
        {
            return int_GetRecords
                (
                i_RecordURIs,
                i_IncludeFileAttachmentContent,
                "Base64",
                false
                );
        }

		internal GrooveWebServicesV12Helpers.Forms.RecordDataSet int_GetRecords(string[] i_RecordURIs, bool i_IncludeFileAttachmentContent, string i_FileAttachmentFormat, bool i_ExceptionIfDeleted)
		{
			GrooveWebServicesV12Helpers.Forms.RecordDataSet NewRecordDataSet;

            //  Get initialized reference to web service
			GrooveFormsWebService.GrooveForms FormsWebService = this.GetInitializedFormsWebService(this.Data);

			System.DateTime BeginDateTime = System.DateTime.Now;

			//  Ask service to provide the list of Forms entries for this tool
			GrooveFormsWebService.FormsRecordDataSet FormsRecordDataSet = FormsWebService.ReadRecords
				(
				i_RecordURIs,
				i_IncludeFileAttachmentContent,
				i_FileAttachmentFormat,
				i_ExceptionIfDeleted
				);

			if (GrooveWebServicesV12Helpers.Context.TraceEnabled)
			{
				System.TimeSpan TimeSpan = System.DateTime.Now.Subtract(BeginDateTime);
				System.Diagnostics.Debug.WriteLine("FormsWebService::ReadRecords, " + TimeSpan.TotalMilliseconds + " ms");
			}

			NewRecordDataSet = new GrooveWebServicesV12Helpers.Forms.RecordDataSet(FormsRecordDataSet);
			return NewRecordDataSet;
		}

		/// <summary>
		/// Retrieve the tool's ToolProperties.
		/// </summary>
		public GrooveWebServicesV12Helpers.Forms.ToolProperties ToolProperties
		{
			get
			{
				GrooveWebServicesV12Helpers.Forms.ToolProperties NewToolProperties;

                //  Get initialized reference to web service
				GrooveFormsWebService.GrooveForms FormsWebService = this.GetInitializedFormsWebService(this.Data);

				System.DateTime BeginDateTime = System.DateTime.Now;

				//  Ask service to provide tool properties
				GrooveFormsWebService.ToolProperties ToolProperties = FormsWebService.ReadToolProperties();

				if (GrooveWebServicesV12Helpers.Context.TraceEnabled)
				{
					System.TimeSpan TimeSpan = System.DateTime.Now.Subtract(BeginDateTime);
					System.Diagnostics.Debug.WriteLine("FormsWebService::ReadToolProperties, " + TimeSpan.TotalMilliseconds + " ms");
				}

				NewToolProperties = new GrooveWebServicesV12Helpers.Forms.ToolProperties(this,	ToolProperties);
				return NewToolProperties;
			}
		}

		/// <summary>
		/// Array of Views defined in the FormsTool.
		/// </summary>
		public GrooveWebServicesV12Helpers.Forms.View[] Views
		{
			get
			{
				System.Collections.ArrayList ViewsArrayList = new System.Collections.ArrayList();

                //  Get initialized reference to web service
				GrooveFormsWebService.GrooveForms FormsWebService = this.GetInitializedFormsWebService(this.Data);

				System.DateTime BeginDateTime = System.DateTime.Now;

				//  Ask service to provide the list of View entries for this tool
				GrooveFormsWebService.FormsView[] Views = FormsWebService.ReadViews();

				if (GrooveWebServicesV12Helpers.Context.TraceEnabled)
				{
					System.TimeSpan TimeSpan = System.DateTime.Now.Subtract(BeginDateTime);
					System.Diagnostics.Debug.WriteLine("FormsWebService::ReadViews, " + TimeSpan.TotalMilliseconds + " ms");
				}

				//  Create array list of Views
				foreach (GrooveFormsWebService.FormsView View in Views)
				{
					GrooveWebServicesV12Helpers.Forms.View NewView = new GrooveWebServicesV12Helpers.Forms.View
						(
						this,
						View
						);

					ViewsArrayList.Add(NewView);
				}

				//  Return array from array list
				return (GrooveWebServicesV12Helpers.Forms.View[])ViewsArrayList.ToArray(typeof(GrooveWebServicesV12Helpers.Forms.View));
			}
		}

		/// <summary>
		/// True if this forms tool is designed.
		/// </summary>
		public bool DesignInitialized
		{
			get
			{
				//  Get initialized reference to web service
				GrooveFormsWebService.GrooveForms FormsWebService = this.GetInitializedFormsWebService(this.Data);

				System.DateTime BeginDateTime = System.DateTime.Now;

				//  Ask service to get design initialization state
				bool IsFormsToolDesignInitialized = FormsWebService.IsFormsToolDesignInitialized();

				if (GrooveWebServicesV12Helpers.Context.TraceEnabled)
				{
					System.TimeSpan TimeSpan = System.DateTime.Now.Subtract(BeginDateTime);
					System.Diagnostics.Debug.WriteLine("FormsWebService::IsFormsToolDesignInitialized, " + TimeSpan.TotalMilliseconds + " ms");
				}

				return IsFormsToolDesignInitialized;
			}
		}

		/// <summary>
		/// Add records to the FormsTool.
		/// </summary>
		/// <param name="i_RecordDataSet">RecordDataSet containing records to be added.</param>
		/// <returns>Array of record URIs.</returns>
		public string[] AddRecords(GrooveWebServicesV12Helpers.Forms.RecordDataSet i_RecordDataSet)
		{
            //  Get initialized reference to web service
			GrooveFormsWebService.GrooveForms FormsWebService = this.GetInitializedFormsWebService(this.Data);

			//  Set parameters
			GrooveFormsWebService.FormsRecordDataSet FormsRecordDataSet = new GrooveFormsWebService.FormsRecordDataSet();
			FormsRecordDataSet.Schema = i_RecordDataSet.Schema;
			FormsRecordDataSet.Data = i_RecordDataSet.Data;

			System.DateTime BeginDateTime = System.DateTime.Now;

			//  Ask service to create records
			string[] RecordURIs = FormsWebService.CreateRecords(FormsRecordDataSet);

			if (GrooveWebServicesV12Helpers.Context.TraceEnabled)
			{
				System.TimeSpan TimeSpan = System.DateTime.Now.Subtract(BeginDateTime);
				System.Diagnostics.Debug.WriteLine("FormsWebService::CreateRecords, " + TimeSpan.TotalMilliseconds + " ms");
			}

			return RecordURIs;
		}

		/// <summary>
		/// Update records in the FormsTool.
		/// </summary>
		/// <param name="i_RecordDataSet">RecordDataSet containing records to be updated.</param>
		public void UpdateRecords(GrooveWebServicesV12Helpers.Forms.RecordDataSet i_RecordDataSet)
		{
			//  Get initialized reference to web service
			GrooveFormsWebService.GrooveForms FormsWebService = this.GetInitializedFormsWebService(this.Data);

			//  Set parameters
			GrooveFormsWebService.FormsRecordDataSet FormsRecordDataSet = new GrooveFormsWebService.FormsRecordDataSet();
			FormsRecordDataSet.Schema = i_RecordDataSet.Schema;
			FormsRecordDataSet.Data = i_RecordDataSet.Data;

			System.DateTime BeginDateTime = System.DateTime.Now;

			//  Ask service to update records
			FormsWebService.UpdateRecords
				(
				FormsRecordDataSet,
				false					//  Exception if deleted
				);

			if (GrooveWebServicesV12Helpers.Context.TraceEnabled)
			{
				System.TimeSpan TimeSpan = System.DateTime.Now.Subtract(BeginDateTime);
				System.Diagnostics.Debug.WriteLine("FormsWebService::UpdateRecords, " + TimeSpan.TotalMilliseconds + " ms");
			}
		}

		/// <summary>
		/// Delete records in the FormsTool.
		/// </summary>
		/// <param name="i_RecordURIs">Array of URIs for the records to be deleted.</param>
		public void RemoveRecords(string[] i_RecordURIs)
		{
			//  Get initialized reference to web service
			GrooveFormsWebService.GrooveForms FormsWebService = this.GetInitializedFormsWebService(this.Data);

			System.DateTime BeginDateTime = System.DateTime.Now;

			//  Ask service to delete records
			FormsWebService.DeleteRecords
				(
				i_RecordURIs, 
				false			// Exception if deleted
				);

			if (GrooveWebServicesV12Helpers.Context.TraceEnabled)
			{
				System.TimeSpan TimeSpan = System.DateTime.Now.Subtract(BeginDateTime);
				System.Diagnostics.Debug.WriteLine("FormsWebService::DeleteRecords, " + TimeSpan.TotalMilliseconds + " ms");
			}
		}

		/// <summary>
		/// Mark records as "read" or "unread".
		/// </summary>
		/// <param name="i_RecordURIs">Array of URIs for the records to be marked as "read" or "unread".</param>
		/// <param name="i_Unread">true to mark "unread", false to mark "read".</param>
		internal void SetUnreadStatus(string[] i_RecordURIs, bool i_Unread)
		{
			//  Get initialized reference to web service
			GrooveFormsWebService.GrooveForms FormsWebService = this.GetInitializedFormsWebService(this.Data);

			System.DateTime BeginDateTime = System.DateTime.Now;

			//  Ask service to update unread status
			FormsWebService.UpdateUnreadMark
				(
				i_Unread,
				i_RecordURIs,
				false			//  Exception if deleted
				);

			if (GrooveWebServicesV12Helpers.Context.TraceEnabled)
			{
				System.TimeSpan TimeSpan = System.DateTime.Now.Subtract(BeginDateTime);
				System.Diagnostics.Debug.WriteLine("FormsWebService::UpdateUnreadMark, " + TimeSpan.TotalMilliseconds + " ms");
			}
		}

		/// <summary>
		/// Replaces the design of target Forms tools with the design of this FormsTool.
		/// </summary>
		/// <param name="i_TargetFormsToolURI">Target forms tool URI.</param>
		/// <returns>Forms tool URI which was updated.</returns>
        public string ReplaceDesign(string i_TargetFormsToolURI)
        {
            string UpdatedFormsToolURI = null;
            
            string[] UpdatedFormsToolURIs = ReplaceDesign(new string[] { i_TargetFormsToolURI });
            if (UpdatedFormsToolURIs.Length > 0)
                UpdatedFormsToolURI = UpdatedFormsToolURIs[0];

            return UpdatedFormsToolURI;
        }

		/// <summary>
		/// Replaces the design of one or more target Forms tools with the design of this FormsTool.
		/// </summary>
		/// <param name="i_TargetFormsToolURIs">Array of target forms tool URIs.</param>
		/// <returns>Array of forms tool URIs which were updated.</returns>
		public string[] ReplaceDesign(string[] i_TargetFormsToolURIs)
		{
			System.Collections.ArrayList UpdatedFormsToolURIs = new System.Collections.ArrayList();

            //  Get initialized reference to web service
			GrooveFormsWebService.GrooveForms FormsWebService = this.GetInitializedFormsWebService(this.Data);

			System.DateTime BeginDateTime = System.DateTime.Now;

			//  Ask service to replace design
			GrooveFormsWebService.FormsDesignReplaceResult[] FormsDesignReplaceResults = FormsWebService.ReplaceDesign(i_TargetFormsToolURIs);

			if (GrooveWebServicesV12Helpers.Context.TraceEnabled)
			{
				System.TimeSpan TimeSpan = System.DateTime.Now.Subtract(BeginDateTime);
				System.Diagnostics.Debug.WriteLine("FormsWebService::ReplaceDesign, " + TimeSpan.TotalMilliseconds + " ms");
			}

			foreach (GrooveFormsWebService.FormsDesignReplaceResult FormsDesignReplaceResult in FormsDesignReplaceResults)
			{
				if (FormsDesignReplaceResult.ReplaceSuccessful)
				{
					UpdatedFormsToolURIs.Add(FormsDesignReplaceResult.FormsToolURI);
				}
				else
				{
					System.Diagnostics.Debug.WriteLine("ReplaceDesign failed for " + FormsDesignReplaceResult.FormsToolURI + " => " + FormsDesignReplaceResult.ResultText);
				}
			}

			//  Return array from array list
			return (string[])UpdatedFormsToolURIs.ToArray(typeof(string));
		}

		private GrooveFormsWebService.GrooveForms GetInitializedFormsWebService(string i_TargetURI)
		{
            if ((m_GrooveForms == null) || Context.ReinitNeeded(m_GrooveForms.GrooveRequestHeaderValue.GrooveRequestKey))
			{
				m_GrooveForms = GrooveWebServicesV12Helpers.Forms.FormsTool.CreateInitializedFormsWebService
					(
					m_IdentityURL,
					i_TargetURI,
					Context
					);
			}
			else
			{
				//  Explicitly overwrite target URL and Timeout
				m_GrooveForms.Url = Context.Host + i_TargetURI;
                m_GrooveForms.Timeout = Context.Timeout;
			}

			return m_GrooveForms;
		}

		#endregion

		#region Forms Event Handling

        protected void IncrementFormsToolSubscriptionCount()
        {
            lock (s_FormsToolEventManagerSortedList)
            {
                if (m_FormsToolEventManagerCount == 0)
                {
                    m_FormsSubscriptionID = GrooveWebServicesV12Helpers.EventManager.AddEventListener
                        (
                        Context,
                        this.IdentityURL,
                        GrooveWebServicesV12Helpers.Shared.GROOVE_WEB_SERVICES_FORMS_EVENT_CLASS,
                        this.Data,
                        GrooveWebServicesV12Helpers.EventManager.s_EventURI,
                        this
                        );
                }

                ++m_FormsToolEventManagerCount;
            }
        }

        protected void DecrementFormsToolSubscriptionCount()
        {
            lock (s_FormsToolEventManagerSortedList)
            {
                --m_FormsToolEventManagerCount;

                if (m_FormsToolEventManagerCount == 0)
                {
                    GrooveWebServicesV12Helpers.EventManager.RemoveEventListener
                        (
                        m_FormsSubscriptionID,
                        this
                        );

                    m_FormsSubscriptionID = null;
                }
            }
        }

        public delegate void OnFormRecordsAddedDelegate(GrooveWebServicesV12Helpers.Forms.RecordDataSet i_RecordDataSet);
        internal event OnFormRecordsAddedDelegate InternalOnFormRecordsAddedEvent;

        /// <summary>
        /// Event fired when records are added to the FormsTool
        /// </summary>
        public event OnFormRecordsAddedDelegate OnFormRecordsAddedEvent
        {
            add
            {
                IncrementFormsToolSubscriptionCount();
                InternalOnFormRecordsAddedEvent += value;
            }
            remove
            {
                InternalOnFormRecordsAddedEvent -= value;
                DecrementFormsToolSubscriptionCount();
            }
        }

        public delegate void OnFormRecordsRemovedDelegate(string[] i_RecordIDs);
        internal event OnFormRecordsRemovedDelegate InternalOnFormRecordsRemovedEvent;

        /// <summary>
        /// Event fired when records are deleted from the FormsTool
        /// </summary>
        public event OnFormRecordsRemovedDelegate OnFormRecordsRemovedEvent
        {
            add
            {
                IncrementFormsToolSubscriptionCount();
                InternalOnFormRecordsRemovedEvent += value;
            }
            remove
            {
                InternalOnFormRecordsRemovedEvent -= value;
                DecrementFormsToolSubscriptionCount();
            }
        }

        public delegate void OnFormRecordsUpdatedDelegate(GrooveWebServicesV12Helpers.Forms.RecordDataSet i_RecordDataSet);
        internal event OnFormRecordsUpdatedDelegate InternalOnFormRecordsUpdatedEvent;

        /// <summary>
        /// Event fired when records are updated in the FormsTool
        /// </summary>
        public event OnFormRecordsUpdatedDelegate OnFormRecordsUpdatedEvent
        {
            add
            {
                IncrementFormsToolSubscriptionCount();
                InternalOnFormRecordsUpdatedEvent += value;
            }
            remove
            {
                InternalOnFormRecordsUpdatedEvent -= value;
                DecrementFormsToolSubscriptionCount();
            }
        }

		internal void RaiseFormRecordsAddedEvent(GrooveFormsWebService.FormsRecordDataSet i_FormsRecordDataSet)
		{
			//  If one or more subscribers, broadcast event
			if (InternalOnFormRecordsAddedEvent != null)
			{
				GrooveWebServicesV12Helpers.Forms.RecordDataSet RecordDataSet = new GrooveWebServicesV12Helpers.Forms.RecordDataSet(i_FormsRecordDataSet);
				InternalOnFormRecordsAddedEvent(RecordDataSet);
			}
		}

		internal void RaiseFormRecordsRemovedEvent(string[] i_RecordIDs)
		{
			//  If one or more subscribers, broadcast event
			if (InternalOnFormRecordsRemovedEvent != null)
				InternalOnFormRecordsRemovedEvent(i_RecordIDs);
		}

		internal void RaiseFormRecordsUpdatedEvent(GrooveFormsWebService.FormsRecordDataSet i_FormsRecordDataSet)
		{
			//  If one or more subscribers, broadcast event
			if (InternalOnFormRecordsUpdatedEvent != null)
			{
				GrooveWebServicesV12Helpers.Forms.RecordDataSet RecordDataSet = new GrooveWebServicesV12Helpers.Forms.RecordDataSet(i_FormsRecordDataSet);
				InternalOnFormRecordsUpdatedEvent(RecordDataSet);
			}
		}

		#endregion

		#region GrooveWebServicesV12HelpersBase Implementation

		public override object BindToObject(ref string[] i_URLParts, int i_URLPartIndex)
		{
			object BindResult = null;
			string RelativeURL = i_URLParts[i_URLPartIndex];
			string[] RelativeURLParts = RelativeURL.Split(new char[]{'#'});

			string ObjectType = RelativeURLParts[0];

			if (ObjectType == "Form")
			{
				string FormURI = this.URI + "/DataModelDelegate/FormID=" + RelativeURLParts[1];
				FormURI = FormURI.Replace("Tools/", "Forms/");

				try
				{
					//  ---------------------------------------------------------------------------------------
					//  HACK ALERT:  Since there is no ReadForm method, must read all forms and do uri match

						foreach (GrooveWebServicesV12Helpers.Forms.Form Form in this.Forms)
						{
							if (Form.URI == FormURI)
							{
								BindResult = Form;
								break;
							}
						}

					//  ---------------------------------------------------------------------------------------
				}
				catch (System.Exception Exception)
				{
					throw new System.Exception("Unable to find Form '" + FormURI +"' (" + Exception.Message + ")");
				}

				//  If there are more url parts, continue binding
				if (i_URLParts.Length > ++i_URLPartIndex)
				{
					GrooveWebServicesV12Helpers.IBindServices IBindServices = (GrooveWebServicesV12Helpers.IBindServices)BindResult;
					BindResult = IBindServices.BindToObject(ref i_URLParts, i_URLPartIndex);
				}
			}
			else if (ObjectType == "View")
			{
				string ViewURI = this.URI + "/DataModelDelegate/ViewID=" + RelativeURLParts[1];
				ViewURI = ViewURI.Replace("Tools/", "Forms/");

				try
				{
					//  ---------------------------------------------------------------------------------------
					//  HACK ALERT:  Since there is no ReadView method, must read all views and do uri match

						foreach (GrooveWebServicesV12Helpers.Forms.View View in this.Views)
						{
							if (View.URI == ViewURI)
							{
								BindResult = View;
								break;
							}
						}

					//  ---------------------------------------------------------------------------------------
				}
				catch (System.Exception Exception)
				{
					throw new System.Exception("Unable to find View '" + ViewURI +"' (" + Exception.Message + ")");
				}
			}
			else
				throw new System.Exception("Unknown forms tool url part - '" + ObjectType + "'");

			return BindResult;
		}

		#endregion

	
		#region IGrooveWebServicesEventCallback Members

		public void ProcessEvent(GrooveEventsWebService.Event i_Event)
		{
			switch (i_Event.EventType)
			{
				case GrooveWebServicesV12Helpers.Shared.GROOVE_FORMS_RECORD_ADD_EVENT_TYPE:
				{
					GrooveEventsWebService.GrooveFormsRecordAddEventData FormsRecordAddEventData = (GrooveEventsWebService.GrooveFormsRecordAddEventData)i_Event.EventData;
					this.RaiseFormRecordsAddedEvent(FormsRecordAddEventData.RecordDataSet);

					break;
				}

				case GrooveWebServicesV12Helpers.Shared.GROOVE_FORMS_RECORD_DELETE_EVENT_TYPE:
				{
					GrooveEventsWebService.GrooveFormsRecordDeleteEventData FormsRecordDeleteEventData = (GrooveEventsWebService.GrooveFormsRecordDeleteEventData)i_Event.EventData;
					this.RaiseFormRecordsRemovedEvent(FormsRecordDeleteEventData.RecordIDs);

					break;
				}

				case GrooveWebServicesV12Helpers.Shared.GROOVE_FORMS_RECORD_UPDATE_EVENT_TYPE:
				{
					GrooveEventsWebService.GrooveFormsRecordUpdateEventData FormsRecordUpdateEventData = (GrooveEventsWebService.GrooveFormsRecordUpdateEventData)i_Event.EventData;
					this.RaiseFormRecordsUpdatedEvent(FormsRecordUpdateEventData.RecordDataSet);

					break;
				}

				default:
				{
					System.Diagnostics.Debug.WriteLine("[FormsTool]Unknown event type: " + i_Event.EventType);
					break;
				}
			}
		}

		#endregion
	}
}
